module Rpbk
  class Holder
    def initialize
      @main_level = Level.new 'main_level'
      @levels = [@main_level]
      @controllers = {}
      @groups = {}
      @layout = nil
    end
    
    def extend_from names
      names ||= []
      names = [names] if names.is_a?(String) || names.is_a?(Symbol)
      names.each do |name|
        name = name.to_sym
        group = find_action(@levels.last.controller_name, name) if @levels.last.group_type == :action
        @levels.last.extend_from(group || find_controller(name) || find_group(name))
      end
    end
    
    def layout 
      @main_level.layout
    end
    
    def set_layout name
      @levels.last.layout = name
    end
    
    def scope 
      @levels.last
    end
    
    def set_scope type, name
      case type
      when :controller
        @controllers[name] = Controller.new name unless find_controller(name)
        @levels << @controllers[name]
      when :action
        raise ActionControllerNotSpecifiedException.new "#{name} should have an controller" unless @levels.last && @levels.last.group_type == :controller
        
        @controllers[@levels.last.name].add_action(name) unless find_action(@levels.last.name, name)
        @levels << find_action(@levels.last.name, name)
      when :group
        @groups[name] = Group.new name unless find_group(name)
        @levels << @groups[name]
      end
    end
    
    def drop_last_scope
      @levels.pop
    end
    
    def add_attr attribute
      @levels.last.add_attr attribute
    end
    
    def find_group name
      @groups[name]
    end
    
    def find_attr name
      @main_level.find_attr(name)
    end
    
    def find_action controller_name, name
      @controllers[controller_name].find_action(name) if @controllers[controller_name]
    end
    
    def find_controller name
      @controllers[name]
    end
  end
  
  class Level
    attr_accessor :layout
    def initialize name
      @group_type, @attributes = :main, {}
    end
    
    def group_type
      @group_type
    end
    
    def add_attr attribute
      @attributes[attribute.key] = attribute
    end
    
    def find_attr name
      @attributes[name]
    end   
    
    def attributes
      @attributes
    end
    
    def extend_from group
      if group
        @attributes.merge! group.attributes 
        @layout = group.layout
      end
    end    
  end
  
  class Group < Level
    attr_accessor :name
    def initialize name
      super name
      @group_type, @name = :group, name
    end
  end
  
  class Controller < Level
    attr_accessor :name
    def initialize name
      super name
      @group_type, @name, @actions = :controller, name, {}
    end
    
    def add_action name
      @actions[name] = Action.new name, @name
    end
    
    def find_action name
      @actions[name]
    end
    
  end
  
  class Action < Level
    attr_accessor :name
    attr_reader :controller_name
    def initialize name, controller_name
      super name
      @controller_name, @name, @group_type = controller_name, name, :action
    end
    
  end

  class Attribute
    attr_accessor :key, :value, :type
    
    def initialize key, value
      @type, @key, @value = :attribute, key, value
    end
    
    def equal? action
      action.class == Attribute && action.key == self.key && action.value && self.value
    end
  end

end